package com.bianmaba.services.datacollection.quartiz;

import org.apache.commons.lang3.time.DateUtils;
import org.quartz.*;
import org.quartz.impl.matchers.EverythingMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;

/**
 * @program: samples
 * @description:
 * @author: Chenjiabin
 * @create: 2019/10/8 11:20
 **/
@Component
public class QuartzTaskManager {
    private static final Logger LOG = LoggerFactory.getLogger(QuartzTaskManager.class);

    private Scheduler scheduler;

    @Autowired
    public void setScheduler(Scheduler scheduler, GlobalJobListener globalJobListener) throws SchedulerException {
        this.scheduler = scheduler;
        this.scheduler.getListenerManager().addJobListener(globalJobListener, EverythingMatcher.allJobs());
    }

    public void addJob(Class<? extends Job> jobClass, String name, String group, JobDataMap data, Boolean replace, Boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        addJob(jobClass, jobKey, data, replace, storeNonDurableWhileAwaitingScheduling);
    }

    public void addJob(Class<? extends Job> jobClass, JobKey jobKey, JobDataMap data, Boolean replace, Boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException {
        try {
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).usingJobData(data).build();
            if (storeNonDurableWhileAwaitingScheduling != null) {
                scheduler.addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling);
            } else {
                scheduler.addJob(jobDetail, replace);
            }
            JobDetail jobKey1 = scheduler.getJobDetail(jobKey);
            System.out.println(jobKey1);
        } catch (Exception e) {
            LOG.error(String.format("创建远程任务调用计划出现异常,[key=%s]", jobKey.getName()), e);
        }
    }

    public void triggerJob(String name, String group) {
        triggerJob(name, group, null);
    }

    public void triggerJob(String name, String group, JobDataMap data) {
        JobKey jobKey = JobKey.jobKey(name, group);
        triggerJob(jobKey, data);
    }

    public void triggerJob(JobKey jobKey) {
        triggerJob(jobKey, null);
    }

    public void triggerJob(JobKey jobKey, JobDataMap data) {
        try {
            if (data != null) {
                scheduler.triggerJob(jobKey, data);
            } else {
                scheduler.triggerJob(jobKey);
            }
        } catch (Exception e) {
            LOG.error(String.format("创建远程任务调用计划出现异常,[key=%s]", jobKey.getName()), e);
        }
    }

    public void deleteJob(String name, String group) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        deleteJob(jobKey);
    }

    public void deleteJob(JobKey jobKey) throws SchedulerException {
        scheduler.deleteJob(jobKey);
        scheduler.interrupt(jobKey);
    }

    public void resumeJob(String name, String group) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        resumeJob(jobKey);
    }

    public void resumeJob(JobKey jobKey) throws SchedulerException {
        scheduler.resumeJob(jobKey);
    }

    public void pauseJob(String name, String group) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        pauseJob(jobKey);
    }

    public void pauseJob(JobKey jobKey) throws SchedulerException {
        scheduler.pauseJob(jobKey);
    }

    public void resumeTrigger(String name, String group) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
        resumeTrigger(triggerKey);
    }

    public void resumeTrigger(TriggerKey triggerKey) throws SchedulerException {
        scheduler.resumeTrigger(triggerKey);
    }


    public void pauseTrigger(String name, String group) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
        pauseTrigger(triggerKey);
    }

    public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException {
        scheduler.pauseTrigger(triggerKey);
    }


    //立即执行一次任务
    public Trigger executeOnceJob(Class<? extends Job> jobClass, String jobName, String jobGroup, JobDataMap data) {
        return executeOnceJob(jobClass, JobKey.jobKey(jobName, jobGroup), data, null);
    }

    //根据延时时间执行一次任务(延时单位：秒)
    public Trigger executeOnceJob(Class<? extends Job> jobClass, String jobName, String jobGroup, JobDataMap data, int delay) {
        return executeOnceJob(jobClass, JobKey.jobKey(jobName, jobGroup), data, delay);
    }

    //在指定时间到了的时候执行一次任务
    public Trigger executeOnceJob(Class<? extends Job> jobClass, String jobName, String jobGroup, JobDataMap data, Date startAt) {
        return executeOnceJob(jobClass, JobKey.jobKey(jobName, jobGroup), data, startAt);
    }

    //根据延时时间执行一次任务(延时单位：秒)
    public Trigger executeOnceJob(Class<? extends Job> jobClass, JobKey jobKey, JobDataMap data, int delay) {
        Date startAt = DateUtils.addSeconds(Calendar.getInstance().getTime(), delay);
        return executeOnceJob(jobClass, jobKey, data, startAt);
    }

    //在指定时间到了的时候执行一次任务
    public Trigger executeOnceJob(Class<? extends Job> jobClass, JobKey jobKey, JobDataMap data, Date startAt) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).usingJobData(data).build();
            //表达式调度构建器(即任务执行的时间)
            TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
            Trigger trigger = null;
            if (scheduler.checkExists(triggerKey)) {
                scheduler.triggerJob(jobKey, data);
                trigger = scheduler.getTrigger(triggerKey);
            } else {
                TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey);

                if (startAt != null) {
                    triggerBuilder.startAt(startAt);
                }
                trigger = triggerBuilder.build();
                scheduler.scheduleJob(jobDetail, trigger);
            }
            LOG.info(String.format("立即执行任务调用成功,[key=%s]", jobKey.getName()));
            return trigger;
        } catch (Exception e) {
            LOG.error(String.format("创建远程任务调用计划出现异常,[key=%s]", jobKey.getName()), e);
        }
        return null;
    }


    //停止计划
    public boolean unscheduleJob(String name, String group) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
        return unscheduleJob(triggerKey);
    }

    //停止计划
    public boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException {
        return scheduler.unscheduleJob(triggerKey);
    }


    //修改计划
    public Trigger rescheduleJob(String jobName, String jobGroup, String cronExpression) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            //表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey, trigger);
            return trigger;
        } catch (Exception e) {
            LOG.error(String.format("创建远程任务调用计划出现异常,[key=%s]", jobName), e);
        }
        return null;
    }

    public Trigger scheduleJob(Class<? extends Job> jobClass, String jobName, String jobGroup, String cronExpression, JobDataMap data) {
        return scheduleJob(jobClass, JobKey.jobKey(jobName, jobGroup), cronExpression, data, null);
    }

    public Trigger scheduleJob(Class<? extends Job> jobClass, String jobName, String jobGroup, String cronExpression, JobDataMap data, Date startAt) {
        return scheduleJob(jobClass, JobKey.jobKey(jobName, jobGroup), cronExpression, data, startAt);
    }

    //(延时单位：秒)
    public Trigger scheduleJob(Class<? extends Job> jobClass, String jobName, String jobGroup, String cronExpression, JobDataMap data, int delay) {
        return scheduleJob(jobClass, JobKey.jobKey(jobName, jobGroup), cronExpression, data, delay);
    }

    //(延时单位：秒)
    public Trigger scheduleJob(Class<? extends Job> jobClass, JobKey jobKey, String cronExpression, JobDataMap data, int delay) {
        Date startAt = DateUtils.addSeconds(Calendar.getInstance().getTime(), delay);
        return scheduleJob(jobClass, jobKey, cronExpression, data, startAt);
    }

    public Trigger scheduleJob(Class<? extends Job> jobClass, JobKey jobKey, String cronExpression, JobDataMap data, Date startAt) {
        try {
            //表达式调度构建器(即任务执行的时间)

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            /**
             * 以下是配置失火策略（超过预定执行时间的毫秒数大于配置文件中misfireThreshold的阀值时为失火）
             *
             *   设置misfire策略：CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
             *   以当前时间为触发频率立刻触发一次执行，然后按照Cron频率依次执行
             *
             *   设置misfire策略：Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
             *          ——以错过的第一个频率时间立刻开始执行 ——重做错过的所有频率周期 ——当下一次触发频率发生时间大于当前时间以后，按照Interval的依次执行剩下的频率
             *          ——共执行RepeatCount+1次
             *
             *   设置misfire策略：CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING = 2
             *          ——不触发立即执行
             *          ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
             */
            scheduleBuilder.withMisfireHandlingInstructionFireAndProceed();

            TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
            TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).forJob(jobKey);
            if (startAt != null) {
                triggerBuilder.startAt(startAt);
            }
            CronTrigger trigger = triggerBuilder.build();
            if (scheduler.checkExists(triggerKey)) {
                scheduler.rescheduleJob(triggerKey, trigger);
                LOG.info(String.format("重置计划成功,[key=%s]", jobKey.getName()));
            } else {
                JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).usingJobData(data).build();
                scheduler.scheduleJob(jobDetail, trigger);
                LOG.info(String.format("创建计划成功,[key=%s]", jobKey.getName()));
            }
            return trigger;
        } catch (Exception e) {
            LOG.error(String.format("创建计划出现异常,[key=%s]", jobKey.getName()), e);
        }
        return null;
    }
}
